﻿#region Namespaces

using System;
using System.IO;
using System.Linq;

using Vibstudio.X4NET.IO.Compression;
using Vibstudio.X4NET.IO.Path;
using Vibstudio.X4NET.Text.Encoding;

#endregion

namespace Vibstudio.X4NET.IO
{
    public static class IOExtensions
    {
        /// <summary>
        /// Convert a file into a byte array and compress it if specified.
        /// </summary>
        /// <param name="filePath">Path of file to convert.</param>
        /// <param name="toZip">Flag indicating whether the file should be zipped before processing.</param>
        /// <returns>Byte array of file to convert.</returns>
        public static byte[] ToBytes(this FilePath filePath, bool toZip = false)
        {
            return !toZip ? File.ReadAllBytes(filePath.Path) : filePath.Compress();
        }

        public static string ToText(this FilePath filePath)
        {
            return File.ReadAllText(filePath.Path);
        }

        public static Stream ToStream(this string text)
        {
            return new MemoryStream(text.ToBytes());
        }

        public static Stream ToStream(this FilePath filePath)
        {
            return new MemoryStream(filePath.ToBytes());
        }

        public static Stream ToStream(this byte[] buffer)
        {
            return new MemoryStream(buffer);
        }

        /// <summary>
        /// Writes the specified byte array to the file compressing or decompressing the contents if specified.
        /// </summary>
        /// <param name="bytes">Content of file to write.</param>
        /// <param name="filePath">Path to write file.</param>
        /// <param name="compressionMode">Compression mode.</param>
        /// <param name="fileEntry">Name of entry file (required only for compression).</param>
        public static void Write(this byte[] bytes, FilePath filePath, CompressionMode compressionMode = CompressionMode.None, string fileEntry = "")
        {
            switch (compressionMode)
            {
                case CompressionMode.Compress:
                    if (string.IsNullOrEmpty(fileEntry)) throw new ArgumentNullException("fileEntry");
                    File.WriteAllBytes(filePath.ZipPath, bytes.Compress(fileEntry));
                    break;
                case CompressionMode.Decompress:
                    File.WriteAllBytes(filePath.Path, bytes.Decompress());
                    break;
                default:
                    File.WriteAllBytes(filePath.Path, bytes);
                    break;
            }
        }

        /// <summary>
        /// Gets a value indicating whether two files are equal.
        /// </summary>
        /// <param name="filePath1">Starting file path on which to perform the comparison.</param>
        /// <param name="filePath2">Destination file path on which to perform the comparison.</param>
        /// <returns>
        /// <c>true</c> if the content of the file are equal; otherwise <c>false</c>.
        /// </returns>
        /// <exception cref="FileNotFoundException">
        /// <paramref name="filePath1"/> file path does not exist.
        /// </exception>
        public static bool AreEqual(this FilePath filePath1, string filePath2)
        {
            if (!File.Exists(filePath1.Path)) throw new FileNotFoundException("File not found", filePath1.FileName);
            if (string.IsNullOrEmpty(filePath2)) return false;
            if (!File.Exists(filePath2)) return false;

            return File.ReadLines(filePath1.Path).SequenceEqual(File.ReadLines(filePath2));
        }
    }
}
